package com.moon.back.util;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.RemovalCause;
import com.github.benmanes.caffeine.cache.RemovalListener;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * Caffeine缓存工具类
 * @param <K> 键类型
 * @param <V> 值类型
 */
@Slf4j
public class CaffeineUtil<K, V> {
    private Cache<K, V> cache;

    // 私有构造方法
    private CaffeineUtil(Builder<K, V> builder) {
        Caffeine<Object, Object> caffeine = Caffeine.newBuilder();
        
        if (builder.initialCapacity > 0) {
            caffeine.initialCapacity(builder.initialCapacity);
        }
        
        if (builder.maximumSize > 0) {
            caffeine.maximumSize(builder.maximumSize);
        }
        
        if (builder.expireAfterWrite > 0) {
            caffeine.expireAfterWrite(builder.expireAfterWrite, TimeUnit.SECONDS);
        }
        
        if (builder.expireAfterAccess > 0) {
            caffeine.expireAfterAccess(builder.expireAfterAccess, TimeUnit.SECONDS);
        }
        
        if (builder.removalListener != null) {
            caffeine.removalListener(builder.removalListener);
        }
        
        if (builder.recordStats) {
            caffeine.recordStats();
        }
        
        this.cache = caffeine.build();
    }

    // region 核心操作方法
    
    /**
     * 获取缓存值（自动加载）
     * @param key 键
     * @param loader 加载器（缓存不存在时调用）
     * @return 值
     */
    public V get(K key, Function<? super K, ? extends V> loader) {
        return cache.get(key, loader);
    }

    /**
     * 直接获取缓存值（不自动加载）
     * @param key 键
     * @return 值或null
     */
    public V getIfPresent(K key) {
        return cache.getIfPresent(key);
    }

    /**
     * 手动存入缓存
     * @param key 键
     * @param value 值
     */
    public void put(K key, V value) {
        cache.put(key, value);
    }

    /**
     * 删除缓存项
     * @param key 键
     */
    public void invalidate(K key) {
        cache.invalidate(key);
    }

    /**
     * 清空缓存
     */
    public void cleanUp() {
        cache.cleanUp();
    }

    /**
     * 获取统计信息（需启用recordStats）
     */
    public String stats() {
        return cache.stats().toString();
    }
    // endregion

    // region Builder模式配置类
    public static class Builder<K, V> {
        private int initialCapacity = -1;
        private long maximumSize = -1;
        private long expireAfterWrite = -1;
        private long expireAfterAccess = -1;
        private RemovalListener<K, V> removalListener;
        private boolean recordStats = false;

        public Builder<K, V> initialCapacity(int initialCapacity) {
            this.initialCapacity = initialCapacity;
            return this;
        }

        public Builder<K, V> maximumSize(long maximumSize) {
            this.maximumSize = maximumSize;
            return this;
        }

        public Builder<K, V> expireAfterWrite(long duration, TimeUnit unit) {
            this.expireAfterWrite = unit.toSeconds(duration);
            return this;
        }

        public Builder<K, V> expireAfterAccess(long duration, TimeUnit unit) {
            this.expireAfterAccess = unit.toSeconds(duration);
            return this;
        }

        public Builder<K, V> removalListener(RemovalListener<K, V> removalListener) {
            this.removalListener = removalListener;
            return this;
        }

        public Builder<K, V> recordStats(boolean recordStats) {
            this.recordStats = recordStats;
            return this;
        }

        public CaffeineUtil<K, V> build() {
            return new CaffeineUtil<>(this);
        }
    }
    // endregion

    // region 使用示例
    public static void main(String[] args) {
        // 1. 创建缓存实例
        CaffeineUtil<String, String> cacheUtil = new CaffeineUtil.Builder<String, String>()
                .initialCapacity(100)
                .maximumSize(1000)
                .expireAfterWrite(5, TimeUnit.MINUTES)
                .removalListener((String key, String value, RemovalCause cause) -> 
                    System.out.println("缓存删除: " + key + ", 原因: " + cause))
                .recordStats(true)
                .build();

        // 2. 使用缓存
        // 自动加载
        String value = cacheUtil.get("user:1001", k -> {
            System.out.println("缓存未命中，从数据库加载");
            return "张三";
        });

        // 直接获取
        String cachedValue = cacheUtil.getIfPresent("user:1001");

        // 手动存储
        cacheUtil.put("config:site_name", "我的网站");

        // 删除缓存
        cacheUtil.invalidate("config:site_name");

        // 查看统计信息
        System.out.println(cacheUtil.stats());
    }
    // endregion
}